﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Algobox.JuicyLib.TimeSeries;

namespace Algobox.JuicyLib.Analysis
{
    public class ExponentialMovingAverage : SimpleMovingAverage
    {

        //http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages

        int tickCount = 0;

        private double currentEMA = 0.0;

        protected double CurrentEMA
        {
            get { return currentEMA; }
            set { currentEMA = value; }
        }

        /// <summary>
        /// will do a shallow copy then 
        /// </summary>
        /// <param name="ts"></param>
        /// <returns></returns>
        public override double? Initialise(BaseTimeSeries ts)
        {
            ts.ShallowCopyBTS(timeseries);

            return CalculateExponentialMovingAverage();
        }
     
        public const int HEAD = 0;

        public virtual double AddTickandCalcEMA(BaseTimeSeriesRecord record)
        {
            double? objEMA = CalculateExponentialMovingAverage(currentEMA, record.RecordValue, tickCount+1);
            
            if(objEMA != null && objEMA.HasValue)
            {
                tickCount++;
                currentEMA = objEMA.Value; 
            }
            else
            {
                objEMA = currentEMA;
            }
            return objEMA.Value;
        }

        int intervalInSeconds = 60;

        public int IntervalInSeconds
        {
            get { return intervalInSeconds; }
            set { intervalInSeconds = value; }
        }
        
        public virtual double AddTickandReCalcEMA(BaseTimeSeriesRecord record)
        {
            timeseries.Add (record);

            DateTime now = record.RecordTime.AddSeconds(-1 * intervalInSeconds);

            timeseries.RemoveTicks(now);

            double? val = CalculateExponentialMovingAverage();

            if (val != null && val.HasValue)
            {
                return val.Value; 
            }
            return record.RecordValue;
        }
        
        protected double? CalculateExponentialMovingAverage()
        {
            double? val = null;

            double EMA = 0;
            double? objEMA = null;
            for (int i = 0; i < timeseries.Count; i++)
            {
                objEMA = CalculateExponentialMovingAverage(EMA, timeseries[i].RecordValue, i + 1);
            
                   if(objEMA != null && objEMA.HasValue)
                   {
                       tickCount++;
                       EMA = objEMA.Value; 
                   }
            }
            if(EMA > 0)
            {
               val = EMA;
               currentEMA = EMA;
            }
            
            return val;
        }

        protected double? ReCalculateExponentialMovingAverage(double previousEMA, double val)
        {
            int ticks = 0;
            //Multiplier" is equal to 2 / (1 + N) 

            double? prevEMA = 0;
            for (int i = 0; i < timeseries.Count; i++)
            {
                double multiplier = 2.0 / (1.0 + (i+1.0));
                prevEMA = CalculateExponentialMovingAverage(previousEMA,val, ticks);
            }

            return previousEMA;
        }

        protected double? CalculateExponentialMovingAverage(double previousEMA,double val, int ticks)
        {
            if (val == 0)
                return null;
            if (previousEMA == 0)
                return val;
            //Multiplier" is equal to 2 / (1 + N) 
            double multiplier = 2.0 / (1.0 + ticks);
            //EMA(current) = ( (Price(current) - EMA(prev) ) x Multiplier) + EMA(prev)
            double EMA = ((val - previousEMA) * multiplier) + previousEMA;
            previousEMA = EMA;
            return EMA;
        }
    }
}
